#include <pigpio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>

#include "pwm_trigger_depthData.h"

#define MAX_GPIOS 32

#define OPT_P_MIN 1
#define OPT_P_MAX 1000
#define OPT_P_DEF 20

#define OPT_R_MIN 1
#define OPT_R_MAX 300
#define OPT_R_DEF 10

#define OPT_S_MIN 1
#define OPT_S_MAX 10
#define OPT_S_DEF 5
#define rdk_cs_record 369 //记录数据
#define cs_bool 369       //判断开启串口
#define printf_bool 369   //判断打印内容

#define SOUNDINGFILEPATH "/home/pi/SoundingFile"

typedef struct
{
    uint32_t first_tick;
    uint32_t last_tick;
    uint32_t pulse_count;
} gpioData_t;

////测深数据文件序号
extern g_fileList g_soundingFileList;

//接收到的GPS数据切割后的数据
extern char g_gps_split_data[15][100];
//接收到的测深数据
extern char g_sounder_recv_data[100];

int g_test_times = 0;
int g_file_name_change_b = 1;

char g_sounding_file_name[50] = {0};

int g_pwm_rdk_cs_record = 0;
int g_pwm_trigger_num = 0; //记录pwm触发次数
int cs_usb_bool = 0;       //值为369则开启cs串口；

static volatile gpioData_t g_gpio_data[MAX_GPIOS];
static volatile gpioData_t l_gpio_data[MAX_GPIOS];

static volatile int g_reset_counts[MAX_GPIOS];

static uint32_t g_mask;

static int g_num_gpios;
static int g_gpio[MAX_GPIOS];

static int g_opt_p = OPT_P_DEF;
static int g_opt_r = OPT_R_DEF;
static int g_opt_s = OPT_S_DEF;
static int g_opt_t = 0;

pthread_mutex_t save_data_to_file_mutex;

/* pwm检测原函数未修改  */
void usage()
{
    fprintf(stderr,
            "\n"
            "Usage: sudo ./freq_count_1 gpio ... [OPTION] ...\n"
            "   -p value, sets pulses every p micros, %d-%d, TESTING only\n"
            "   -r value, sets refresh period in deciseconds, %d-%d, default %d\n"
            "   -s value, sets sampling rate in micros, %d-%d, default %d\n"
            "\nEXAMPLE\n"
            "sudo ./freq_count_1 4 7 -r2 -s2\n"
            "Monitor gpios 4 and 7.  Refresh every 0.2 seconds.  Sample rate 2 micros.\n"
            "\n",
            OPT_P_MIN, OPT_P_MAX,
            OPT_R_MIN, OPT_R_MAX, OPT_R_DEF,
            OPT_S_MIN, OPT_S_MAX, OPT_S_DEF);
}

/* pwm检测原函数未修改  */
void fatal(int show_usage, char *fmt, ...)
{
    char buf[128];
    va_list ap;

    va_start(ap, fmt);
    vsnprintf(buf, sizeof(buf), fmt, ap);
    va_end(ap);

    fprintf(stderr, "%s\n", buf);

    if (show_usage)
    {
        usage();
    }

    fflush(stderr);

    exit(EXIT_FAILURE);
}

/*******************************************************************
** 函数名:     judgeDirIsExit
** 函数描述:   判断文件夹是否存在不存在则创建
********************************************************************/
int judgeDirIsExit(char *dirPath)
{
    if (access(dirPath, 0) == -1)
    {
        printf("dir is not exist!!!!!\r\n");
        int flag = mkdir(dirPath, 0777);
        if (flag == 0)
        {
            printf("mkdir ok\n");
            return 1;
        }
        else
        {
            printf("mkdir fail\n");
            return 0;
        }
    }
    return 1;
}

/*******************************************************************
** 函数名:     getFileName
** 函数描述:   通过时间获取文件名
********************************************************************/
void getFileName()
{
    time_t curTime;
    struct tm *timeNow;
    time(&curTime);
    timeNow = localtime(&curTime);

    g_test_times++;
    sprintf(g_sounding_file_name, "%d_%d_%d_%d-%d", timeNow->tm_year + 1900, timeNow->tm_mon + 1, timeNow->tm_mday, timeNow->tm_hour, g_test_times);
    printf(g_sounding_file_name);
    g_file_name_change_b = 0;
    g_pwm_trigger_num = 1;
}

/*******************************************************************
** 函数名:     setFileNameChange
** 函数描述:   当pwm触发时长大于15分钟时，改变写入数据时的文件名
********************************************************************/
void setFileNameChange()
{
    g_file_name_change_b = 1;
}

/*******************************************************************
** 函数名:     save_file
** 函数描述:   测深数据保存
********************************************************************/
int save_file(int pwm_trigger_num)
{
    pthread_mutex_lock(&save_data_to_file_mutex);
    FILE *save_fd = NULL;
    char fullFilePath[100] = {0};

    //test
    // alarm(60);
    alarm(900);
    signal(SIGALRM, setFileNameChange);

    if (!judgeDirIsExit(SOUNDINGFILEPATH))
    {
        printf("fail to mk PUMPDATADIRPATH!\n");
        return 0;
    }

    if (g_file_name_change_b != 0)
    {
        getFileName();
    }

    if (g_soundingFileList.FileNum < MAX_FILE_NUM)
    {
        g_soundingFileList.FileNum++;
    }
    else
    {
        g_soundingFileList.FileNum = 1;
    }
    sprintf(fullFilePath, "%s/%d_%s.txt", g_soundingFileList.FileNum, SOUNDINGFILEPATH, g_sounding_file_name);
    // printf(fullFilePath);
    file_Contrast(SOUNDINGFILEPATH, g_soundingFileList.FileNum);
    save_fd = fopen(fullFilePath, "a+"); //创建，如果文件已存在，数据写入文件末尾
    if (save_fd == NULL)                 //还是空，创建失败
    {
        printf("save_fd fopen is NULL\n");
        return 0;
    }
    fprintf(save_fd, "%d      %s    %s%s--%s%s--h1:%s--h2:%s\n", pwm_trigger_num, g_sounder_recv_data, g_gps_split_data[2], g_gps_split_data[3], g_gps_split_data[4], g_gps_split_data[5], g_gps_split_data[9], g_gps_split_data[11]);
    fclose(save_fd);
    upFileNum(SOUNDING_CONFIG_FILE_PATH, g_soundingFileList.FileNum);
    return 1;
    pthread_mutex_unlock(&save_data_to_file_mutex);
}

/*******************************************************************
** 函数名:     pwm_rdk_cs_save_data
** 函数描述:   pwm触发保存数据
** 函数返回：   
********************************************************************/
int pwm_rdk_cs_save_data()
{
    pthread_t save_file_thread = NULL;
    if (g_pwm_rdk_cs_record == rdk_cs_record) //如果全局变量改变为rdk_cs_record
    {
        g_pwm_trigger_num++;
        if ((pthread_create(&save_file_thread, NULL, save_file, g_pwm_trigger_num)) == -1)
        {
            printf("create update send data thread error!\n");
        }
        // save_file(); //保存数据
        printf("开始保存,第%d次保存\n", g_pwm_trigger_num);
        g_pwm_rdk_cs_record = 0; //pwm触发一次只保存一次，置0等待下一次触发
    }
    return 0;
}

/*******************************************************************
** 函数名:     edges
** 函数描述:   pwm电平触发
********************************************************************/
void edges(int gpio, int level, uint32_t tick)
{
    if (level == 0) //高电平
    {
        static int trigger = 0;
        l_gpio_data[gpio].first_tick = tick;
        static int diff = 0;                                               //检测pwm占空比，高电平时间
        diff = g_gpio_data[gpio].first_tick - g_gpio_data[gpio].last_tick; //高电平时间

        // printf("高: %d\n", diff);
        if ((1900 <= diff && diff <= 2000) && (trigger == 0)) //
        {
            printf("打开 %d\n", diff);
            g_pwm_rdk_cs_record = rdk_cs_record; //使用全局变量控制写入数据到文件
            pwm_rdk_cs_save_data();              //写入数据函数
            trigger = 1;                         //防止多次触发，过滤相同信号
        }
        if ((800 <= diff && diff < 1900) && (trigger == 1))
        {
            printf("关闭 %d\n", diff);
            g_pwm_rdk_cs_record = 0;
            trigger = 0;
        }
    }
    else //低电平时间
    {
        l_gpio_data[gpio].last_tick = tick;
        int diff = g_gpio_data[gpio].last_tick - g_gpio_data[gpio].first_tick;
        // printf("低: %d\n", diff);
    }
}

void pwmInit()
{
    int i, rest, g, wave_id, mode, diff, tally;
    gpioPulse_t pulse[2];
    int count[MAX_GPIOS];

    g_num_gpios = 0;

    g = 17; //原主函数参数，修改为检测gpio 0

    g_gpio[g_num_gpios++] = g;
    g_mask |= (1 << g);

    if (!g_num_gpios)
        fatal(1, "At least one gpio must be specified");

    printf("Monitoring gpios");
    for (i = 0; i < g_num_gpios; i++)
        printf(" %d", g_gpio[i]);
    printf("\nSample rate %d micros, refresh rate %d deciseconds\n",
           g_opt_s, g_opt_r);

    gpioCfgClock(g_opt_s, 1, 1);

    gpioInitialise();

    gpioWaveClear();

    pulse[0].gpioOn = g_mask;
    pulse[0].gpioOff = 0;
    pulse[0].usDelay = g_opt_p;

    pulse[1].gpioOn = 0;
    pulse[1].gpioOff = g_mask;
    pulse[1].usDelay = g_opt_p;

    gpioWaveAddGeneric(2, pulse);

    wave_id = gpioWaveCreate();

    /* monitor g_gpio level changes */

    for (i = 0; i < g_num_gpios; i++)
    {
        printf("**********************************\n");
        gpioSetAlertFunc(g_gpio[i], edges);
    }
    mode = PI_INPUT;

    if (g_opt_t)
    {
        gpioWaveTxSend(wave_id, PI_WAVE_MODE_REPEAT);
        mode = PI_OUTPUT;
    }

    for (i = 0; i < g_num_gpios; i++)
        gpioSetMode(g_gpio[i], mode);

    while (1)
    {
        gpioDelay(10000); //修改检测延迟时间，原为1秒，降低延迟

        for (i = 0; i < g_num_gpios; i++)
        {
            g = g_gpio[i];
            g_gpio_data[g] = l_gpio_data[g];

            diff = g_gpio_data[g].last_tick - g_gpio_data[g].first_tick;
            tally = g_gpio_data[g].pulse_count;
            if (diff == 0)
                diff = 1;

            g_reset_counts[g] = 1;
            //  printf("g=%d %.0f (%d/%d)\n",
            //     g, 1000000.0 * tally / diff, tally, diff);
        }
    }
}
